package com.sunsharing.flow.exe;

import com.sun.corba.se.impl.ior.OldJIDLObjectKeyTemplate;
import com.sunsharing.common.Context;
import com.sunsharing.common.ContextCreate;
import com.sunsharing.common.FlowMsg;
import com.sunsharing.common.config.Config;
import com.sunsharing.common.utils.StringUtils;
import com.sunsharing.flow.WorkFlowException;
import com.sunsharing.flow.model.Node;
import com.sunsharing.flow.model.Transition;
import com.sunsharing.flow.model.node.EndNode;
import com.sunsharing.flow.model.node.TaskNode;
import org.apache.log4j.Logger;

import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: criss
 * Date: 13-5-4
 * Time: 下午6:09
 * To change this template use File | Settings | File Templates.
 */
public class Token extends FlowMsg {

    //主键
    long id = 0;

    //名称
    protected String name = null;


    //开始时间
    protected String startTime = null;

    //结束时间
    protected String endTime = null;

    //当前节点
    transient protected Node node = null;

    String nodeId;

    //令牌的开始节点
    transient protected Node startNode;

    //令牌的结束节点
    transient protected Node endNode;

    //流程实例
    protected ProcessInstance processInstance = null;

    //父token
    protected Token parent = null;

    //子token
    protected Map children = null;

    //是否挂起
    protected boolean isSuspended = false;

    //回退标志: false:未回退 1:在回退
    private boolean backBz = false;

    //撤回标志 false:未撤回 1:在撤回
    private boolean withdrawBz = false;

    //状态
//    protected int status;

    /**平台上下文*/
    protected Context context;

    /**已流转过的节点**/
    //protected List executedNodes = new ArrayList();

    /**关联的任务**/
//    protected List tasks = new ArrayList();
    /**流程参数*/
    Map rootPar = new HashMap();
    Map childPar = new HashMap();

    protected String andForkNode = "";
    protected String andForkTaskId = "";

//    /**运行**/
//    public static final int STATUS_RUN = 0;
//
//    /**结束**/
//    public static final int STATUS_END = 9;
//
//    /**挂起**/
//    public static final int STATUS_SUSPEND = 1;

    /**终止**/
    //public static final int STATUS_TERMINATE = 2;

    /**
     * 功能描述:
     *     创建token
     * @param processInstance ProcessInstance
     * @param startNode Node
     */
    public Token(ProcessInstance processInstance, Node startNode) {
        this.startTime = StringUtils.getCurrentTime();
        this.processInstance = processInstance;
        this.setNode(startNode);
        this.startNode = startNode;

    }

    /**
     * 功能描述:
     *     创建令牌
     * @param parent Token
     * @param name String
     */
    public Token(Token parent, String name) {
        this.startTime = StringUtils.getCurrentTime();
        this.processInstance = parent.getProcessInstance();
        this.name = name;
        this.node = parent.getNode();
        this.parent = parent;
        this.rootPar.putAll(parent.getRootPar());
        parent.addChild(this);

    }

    /**
     * 功能描述:
     *     创建令牌
     * @param parent Token
     * @param name String
     */
    public Token(Token parent, String name, Node startNode,Context context,String taskId) {
        this(parent, name);
        this.startNode = startNode;
        this.context = context.clone();
        this.context.setMsg(this);
        this.andForkNode = Config.getInstance().getNodeId();
        this.andForkTaskId = taskId;
    }

    /**
     * 功能描述:
     *     增加子令牌
     * @param token Token
     */
    public void addChild(Token token) {
        if (children == null) {
            children = new HashMap();
        }
        children.put(token.getName(), token);
    }
    /**
     * 功能描述:
     *    根据指定的迁移激活令牌
     * @param transition Transition
     * @param executionContext ExecutionContext
     */
    public void signal(Transition transition, ExecutionContext executionContext)
    {
        if(getNode() instanceof EndNode)
        {
            return;
        }

        getLogger().debug("进入token...." + "关联的node:"
                + getNode().getId() + " name:" + getNode().getName());

        if (transition == null) {
            throw new WorkFlowException(
                    "指定的迁移为空,不能启动令牌!");
        }
        if (executionContext == null) {
            throw new WorkFlowException(
                    "执行上下文为空,不能启动令牌!");
        }
        //如果令牌被挂起,则抛出异常
        if (this.isSuspended()) {
            throw new WorkFlowException("令牌已被挂起,不能启动令牌!");
        }

        //设置上下文的当前的迁移
        executionContext.setTransition(transition);
        //设置上下文的当前节点
        executionContext.setNode(getNode());
        getLogger().debug("token中转移::" + getNode().getName() + " id: " + getNode().getId());
        //节点离开
        getNode().leave(executionContext, transition);
    }

    public void otherNodeExecute()
    {
        ExecutionContext context = new ExecutionContext(this);
        getNode().execute(context);
    }

    public void leaveCurrentNode(String result)
    {
        if(getNode() instanceof TaskNode)
        {
            String output = ((TaskNode)getNode()).getCallChain().getOutput();
            if(isRoot())
            {
                this.rootPar.put(output,result);
            }else
            {
                this.childPar.put(output,result);
            }
        }

        ExecutionContext context = new ExecutionContext(this);
        getNode().leave(context);
    }


    public Object getPar(String key)
    {
        if(childPar.get(key)!=null)
        {
            return childPar.get(key);
        }else
        {
            return rootPar.get(key);
        }
    }

    public Map getAllPar()
    {
        HashMap h = new HashMap();
        if(childPar.keySet().size()>0)
        {
            h.putAll(childPar);
        }
        if(rootPar.keySet().size()>0)
        {
             h.putAll(rootPar);
        }
        return h;
    }

    public void putPar(String key,Object value)
    {
        if(isRoot())
        {
            rootPar.put(key,value);
        }else
        {
            childPar.put(key,value);
        }
    }

    public void signal()
    {
        if(getNode() instanceof EndNode)
        {
            return;
        }
        Transition deFault = this.getNode().getDefaultLeavingTransition();
        if (getNode() == null) {
            throw new WorkFlowException("该令牌没有关联节点,导致该令牌不能被启动!");
        }

        if (getNode().getDefaultLeavingTransition() == null) {
            throw new WorkFlowException("节点:" + getNode() + "没有默认的离开迁移,导致"
                    + "该令牌不能被启动!");
        }

        ExecutionContext context = new ExecutionContext(this);
        context.setNode(getNode());
        context.setTransition(deFault);
        //激活默任迁移
        signal(getNode().getDefaultLeavingTransition(), context);
    }



    /**
     * 功能描述:
     *    判断是否挂起
     * @return boolean
     */
    public boolean isSuspended() {
//        if (this.status == this.STATUS_SUSPEND) {
//            return true;
//        } else {
//            return false;
//        }
        return false;
    }

    /**
     * 功能描述:
     *     增加一个节点
     * @param node Node
     */
    public void addExecutedNode(Node node) {
//        ExecutedNode executedNode = new ExecutedNode(node);
//        executedNode.setExecutedOrder(this.executedNodes.size());
//        executedNode.setToken(this);
//        this.executedNodes.add(executedNode);
    }

    public void setEndNode(Node endNode) {
        this.endNode = endNode;
    }

    /**
     * 功能描述:
     *    判断是否根令牌
     * @return boolean
     */
    public boolean isRoot() {
        return (parent == null);
    }

    /**
     * 功能描述:
     *    结束令牌
     */
    public void end() {

       // this.status = this.STATUS_END;

        //如果没有结束
        if (endTime == null) {

            this.endTime = StringUtils.getCurrentTime();
            if(this.parent!=null)
            {
                this.parent.getChildPar().putAll(this.childPar);
            }

            //结束子token
            if (children != null) {
                Iterator iter = children.values().iterator();
                while (iter.hasNext()) {
                    Token child = (Token) iter.next();
                    if (!child.hasEnded()) {
                        child.end();
                    }
                }
            }

            //结束流程
           if(isRoot())
           {
               //如果是根节点,回退,调用流程
               this.getProcessInstance().end();
           }


//
//            //如果是rootToken,则结束流程实例
//            if (isRoot()) {
//                this.getProcessInstance().end();
//            }

        }

    }

    /**
     * 功能描述:
     *    判断该令牌是否结束
     * @return boolean
     */
    public boolean hasEnded() {
        //如果时间为结束
        if (StringUtils.isBlank(this.endTime)) {
            return false;
        } else {
            return true;
        }
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getStartTime() {
        return startTime;
    }

    public void setStartTime(String startTime) {
        this.startTime = startTime;
    }

    public String getEndTime() {
        return endTime;
    }

    public void setEndTime(String endTime) {
        this.endTime = endTime;
    }

    public Node getNode() {
        if(node==null)
        {
            node = processInstance.getDefinition().getNodeById(this.nodeId);
            startNode = processInstance.getDefinition().getStartNode();
            endNode = processInstance.getDefinition().getEndNode();
        }
        return this.node;
    }

    public void setNode(Node node) {
        this.node = node;
        this.nodeId = node.getId();
    }

    public Node getStartNode() {
        if(startNode==null)
        {
            startNode = processInstance.getDefinition().getStartNode();
            endNode = processInstance.getDefinition().getEndNode();
        }
        return startNode;
    }

    public void setStartNode(Node startNode) {
        this.startNode = startNode;
    }

    public Node getEndNode() {
        if(startNode==null)
        {
            startNode = processInstance.getDefinition().getStartNode();
            endNode = processInstance.getDefinition().getEndNode();
        }
        return this.endNode;
    }

    public void resetServiceToflow()
    {
        this.serviceId = processInstance.getDefinition().getId();
    }


    public Token getParent() {
        return parent;
    }

    public void setParent(Token parent) {
        this.parent = parent;
    }

    public Map getChildren() {
        return children;
    }

    public void setChildren(Map children) {
        this.children = children;
    }

    public boolean isBackBz() {
        return backBz;
    }

    public void setBackBz(boolean backBz) {
        this.backBz = backBz;
    }

    public boolean isWithdrawBz() {
        return withdrawBz;
    }

    public void setWithdrawBz(boolean withdrawBz) {
        this.withdrawBz = withdrawBz;
    }

    public Map getChildPar() {
        return childPar;
    }

    public void setChildPar(Map childPar) {
        this.childPar = childPar;
    }

    public Map getRootPar() {
        return rootPar;
    }

    public void setRootPar(Map rootPar) {
        this.rootPar = rootPar;
    }

    //    public int getStatus() {
//        return status;
//    }
//
//    public void setStatus(int status) {
//        this.status = status;
//    }

//    public List getExecutedNodes() {
//        return executedNodes;
//    }
//
//    public void setExecutedNodes(List executedNodes) {
//        this.executedNodes = executedNodes;
//    }

//    public List getTasks() {
//        return tasks;
//    }
//
//    public void setTasks(List tasks) {
//        this.tasks = tasks;
//    }

    public void addPar(Map par)
    {
        if(isRoot())
        {
            this.rootPar.putAll(par);
        }else
        {
            this.childPar.putAll(par);
        }
        //this.par.putAll(par);
    }

    public ProcessInstance getProcessInstance() {
        return processInstance;
    }

    public void setProcessInstance(ProcessInstance processInstance) {
        this.processInstance = processInstance;
    }




    public Context getContext() {
        return context;
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public String getAndForkNode() {
        return andForkNode;
    }

    public void setAndForkNode(String andForkNode) {
        this.andForkNode = andForkNode;
    }

    public String getAndForkTaskId() {
        return andForkTaskId;
    }

    public void setAndForkTaskId(String andForkTaskId) {
        this.andForkTaskId = andForkTaskId;
    }
}
